home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
stpdos12.arc
/
STEPDOS.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-12-05
|
79KB
|
2,853 lines
PAGE 60,132
TITLE 'Step DOS Calls'
NAME STEPDOS
;
; ***********************************************************
; * *
; * S T E P D O S *
; * *
; * Rev 1.2 *
; * *
; * Nov 21, 1987 *
; * *
; * Mike Parker *
; * 2374 Meadowpark Court *
; * Maryland Heights, MO 63043 *
; * *
; * CIS 70270,161 *
; * *
; * This program allows you to step through the execution *
; * of another program by intercepting all calls to DOS *
; * INT 21H. A window will pop up displaying all register *
; * values and a short description of the DOS function *
; * being called. Program execution will continue when *
; * you press a key. You can optionally break again after *
; * the DOS function completes so you can see the result *
; * code in the AX register along with important flags. *
; * *
; ***********************************************************
;
; Changes for version 1.1:
; Made STEPDOS a COM file instead of EXE.
; Implement arrow keys to reposition window.
; Only keep as much memory as needed for STEPDOS instead of 64K.
; Doesn't add <NULL> to command line string passed to target program.
; Changed stack switching in 'New21'.
; Recognize DOS switch character ('/') in command line.
; Use 'FIND FIRST' function 4eh when searching for target program
; instead of trying to do 'OPEN'.
; Support monochrome cards.
; Display window on screen even if target program changes video page.
; Change 'Disp_09' code to stop display at '$' terminator.
; Ver 1.0 did not return the IF bit in the flag register to the user's
; original state.
;
; Changes for version 1.2:
; Added window movement using HOME, PGUP, END and PGDN keys to
; move to the four corners of the screen.
; Display version string on top of window.
;
;
; To run, type STEPDOS <filename>
; where <filename> is the full pathname of an EXE or COM file.
;
;
TESTING EQU 0
BG EQU 10H ; BG sets background color (10h = BLUE)
BLACK EQU 00H + BG
BLUE EQU 01H + BG
GREEN EQU 02H + BG
CYAN EQU 03H + BG
RED EQU 04H + BG
MAGENTA EQU 05H + BG
BROWN EQU 06H + BG
WHITE EQU 07H + BG
GRAY EQU 08H + BG
LTBLUE EQU 09H + BG
LTGREEN EQU 0AH + BG
LTCYAN EQU 0BH + BG
LTRED EQU 0CH + BG
LTMAGENTA EQU 0DH + BG
YELLOW EQU 0EH + BG
HIWHITE EQU 0FH + BG
;
CR EQU 13
LF EQU 10
BIGR EQU 1352H ; 'R' key
SMALLR EQU 1372H ; 'r'
BIGS EQU 1F53H ; 'S' key
SMALLS EQU 1F73H ; 's'
ESCAPE EQU 011BH
HOME EQU 4700H
UPARROW EQU 4800H
PGUP EQU 4900H
LEFTARROW EQU 4B00H
RIGHTARROW EQU 4D00H
XEND EQU 4F00H
DOWNARROW EQU 5000H
PGDN EQU 5100H
;
BLANK EQU 32
BRDROW EQU 205
BRDCOL EQU 186
ULC EQU 201
URC EQU 187
LLC EQU 200
LRC EQU 188
;
REGBX EQU 00 ; offsets on saved register stack
REGCX EQU 02
REGDX EQU 04
REGDI EQU 06
REGSI EQU 08
REGBP EQU 10
REGES EQU 12
;
IF TESTING
INT21OFF EQU 0e0h*4 ; during testing an unused INT is used
ELSE
INT21OFF EQU 21h*4
ENDIF
Code SEGMENT PUBLIC PARA 'CODE'
ASSUME CS:Code, DS:Code
ORG 100h
Main: ; starting point
cli
cld
mov AX,CS
mov SS,AX
mov SP,OFFSET Pstack
mov BX,DS ; get difference between segments
sub AX,BX ; so .EXE file can run during testing
;
mov BX,OFFSET PRSIZE ; program size in bytes
mov CL,4
shr BX,CL ; convert it to paragraphs
add BX,AX ; add difference between segments
inc BX ; make it next multiple of 16 bytes
mov AH,4ah ; modify memory block size
int 21h
sti
;
; Copy command line from PSP to local area
;
mov AX,CS
mov ES,AX ; change ES to be local area
;
mov SI,0080h
mov CL,[SI] ; get command line character count
or CL,CL ; zero char count in cmd line?
jnz notzcl
mov AX,CS ; yes, display 'Usage' message
mov DS,AX ; and exit
mov DX,OFFSET Umsg
mov AH,9
int 21h
jmp exit
notzcl:
xor CH,CH
inc SI
mov DI,OFFSET PSPstr
rep movsb ; copy command line
xor AL,AL
stosb ; <NULL> terminator at end
;
mov BX,002ch
mov BX,[BX] ; get segment addr of environment from PSP
;
mov AX,CS
mov DS,AX ; change DS to local area
mov SegEnv,BX ; save in EXEC control block
;
; Check equipment list to see if we have graphics or monochrome card
;
int 11h
and AX,0030h ; save video mode
mov BX,0b000h
cmp AX,0030h ; monochrome?
jz setcrd
mov BX,0b800h ; no, graphics card
setcrd:
mov Scrseg,BX ; save base segment
;
; Calculate starting address on screen for window
;
mov BX,OFFSET W1 ; window parameters
call Window_Parms ; calc start addr of window, wid and ht
;
; Do DOS call to allocate memory
;
mov CL,4
shr AX,CL ; divide by 16 to get # paragraphs
inc AX ; handle any remainder
mov BX,AX
mov AH,48h ; 'allocate memory' DOS call
int 21h
mov Winseg,AX ; save returned segment
jnc cpynam
mov DX,OFFSET Memerr ; ERROR - display string
mov AH,9
int 21h
jmp exit ; and terminate
;
; Copy target program name
;
cpynam:
mov AX,3700h ; get DOS switch character
int 21h
mov Sw_Char,DL
;
mov SI,OFFSET PSPstr + 1
mov DI,OFFSET Filename
xor CX,CX ; zero char count
fnlp:
mov AL,[SI]
cmp AL,' ' ; look for <SP>
jz fndn
cmp AL,00 ; or <NULL> terminator
jz fndn
cmp AL,Sw_Char ; or switch character ('/')
jz fndn
movsb
inc CX ; count number of filename char's
jmp fnlp
fndn:
or CX,CX
jnz gotfn
mov DX,OFFSET Findmsg ; error if zero filename length
mov AH,9
int 21h
jmp freemem
gotfn:
xor AL,AL
stosb
mov FNsize,CX
;
; Copy command line string
; SI -> first parameter after filename
;
mov DI,OFFSET CLstr + 1
xor CX,CX ; zero char count
cllp:
cmp BYTE PTR [SI],00 ; look for <NULL> terminator
jz dncl
movsb
inc CX ; count number of cmd line char's
jmp cllp
dncl:
mov AL,CR ; put <CR> past end
stosb
mov CLstr,CL ; store cmd line count
;
; Build EXEC control block
;
mov SegCmd,OFFSET CLstr
mov SegCmd+2,DS
mov FCBptr1,OFFSET FCB1
mov FCBptr1+2,DS
mov FCBptr2,OFFSET FCB2
mov FCBptr2+2,DS
;
; Parse first parameter
;
mov SI,OFFSET CLstr + 1
mov DI,OFFSET FCB1
mov AL,01 ; scan past separators
mov AH,29h
int 21h
;
; Parse second parameter
;
mov DI,OFFSET FCB2
mov AL,01 ; scan past separators
mov AH,29h
int 21h
;
; Try to find target file
;
call Find_File
jnc redirect ; jump if found it
;
; File not found, display msg and exit
;
mov DI,OFFSET Filename
xor AL,AL ; find terminating <NULL>
mov CX,0ffffh ; there must be one in there somewhere
repne scasb
dec DI
mov AL,27h ; closing quote
stosb
mov AL,'$' ; put string terminator for DOS function 09
stosb
;
mov DX,OFFSET Findmsg ; not found message
mov AH,9
int 21h
;
mov DX,OFFSET Filename ; show filename we were looking for
mov AH,9
int 21h
jmp freemem
;
; Redirect INT 21h
;
redirect:
push ES
cli
mov AX,0
mov ES,AX
mov AX,OFFSET New21
xchg AX,ES:[INT21OFF]
mov Save21,AX
mov AX,CS
xchg AX,ES:[INT21OFF+2]
mov Save21+2,AX
sti
pop ES
;
; Execute target program
;
mov SP,OFFSET Tstack
IF TESTING
include test.asm
clc ; no error
ELSE
mov DX,OFFSET Filename
mov BX,OFFSET Param_Block
mov AH,4bh
mov AL,0
int 21h
ENDIF
;
cli
mov AX,CS ; restore segment registers
mov DS,AX
mov ES,AX
mov SS,AX
mov SP,OFFSET Pstack
jnc execdn
;
; Failed to execute target program. Display message and quit
;
mov DX,OFFSET Execmsg
mov AH,9
int 21h
;
; Restore INT 21h vector
;
execdn:
cli
mov AX,0
mov ES,AX
mov AX,Save21
mov ES:[INT21OFF],AX
mov AX,Save21+2
mov ES:[INT21OFF+2],AX
sti
;
; Free allocated memory from window save area
;
freemem:
mov ES,Winseg
mov AH,49h
int 21h
exit:
mov AH,4ch ; terminate process
mov AL,00
int 21h ; won't return
;
;
; Search for file. If no extention specified try both .COM and .EXE
;
Find_File:
mov DI,OFFSET Filename
mov CX,FNsize ; get program filename size
mov AL,'.'
repne scasb ; check for '.' in target program filename
jz fndext ; jump if found extention
;
; No extention found, try appending '.COM'
;
mov SI,OFFSET COMstr
mov DI,OFFSET Filename
add DI,FNsize
mov CX,4
rep movsb
;
; See if the target program exists before we change the Int 21h vector
; and EXEC it.
;
mov AH,4eh ; find first filename
mov CX,00 ; attribute code
mov DX,OFFSET Filename
int 21h
jnc fret ; jump if file found
;
; FIND with '.COM' extention failed, try appending '.EXE'
;
mov SI,OFFSET EXEstr
mov DI,OFFSET Filename
add DI,FNsize
mov CX,4
rep movsb
;
; Try to find the '.EXE' version of the file
;
fndext:
mov AH,4eh
mov CX,00 ; attribute code
mov DX,OFFSET Filename
int 21h
fret:
ret ; carry flag has error status
;
; INT 21h will be redirected to here
;
New21:
push AX ; use USERS'S stack for first 3 words
push DS
pushf ; push them but we don't need them here
;
cli
mov AX,CS ; now switch to internal stack
mov DS,AX
mov SSsave,SS
mov SPsave,SP
mov SS,AX
mov SP,OFFSET Pstack
sti
;
push ES
push BP
push SI
push DI
push DX
push CX
push BX
mov BP,SP ; save base pointer to display reg's
mov ES,AX
mov AL,Run_Flg
test AL,0ffh ; should we stop and display?
jz norun ; no, restore registers and leave
;
; Recover registers on USER'S stack
;
push ES
les BX,Ssave
mov AX,ES:[BX+2] ; get DS
mov DSsave,AX
mov AX,ES:[BX+4] ; get AX
mov AXsave,AX
mov AX,ES:[BX+6] ; get IP
mov IPsave,AX
mov AX,ES:[BX+8] ; get CS
mov CSsave,AX
mov AX,ES:[BX+10] ; get FLAGS on entry
mov FLsave,AX
pop ES
;
cld ; clear direction flag for string operations
mov AL,Skip_Flg
test AL,0ffh ; skip certain functions?
jz noskip ; no, continue
mov AX,AXsave ; get USER's AX register with function code
cmp AH,Skip_Typ ; compare upper half to type to skip
jz norun ; don't want to break on this one again
mov AL,00 ; skip flag was set but this is new
mov Skip_Flg,AL ; function, so break from now on
noskip:
call Open_Window
call Show_Regs
call Show_Help
call Disp_Text ; Display description string of DOS function
;
call Get_Key ; wait for a key pressed
call Disp_Key ; dispatch to key handler
jc noskip ; if carry set, need to redisplay window
call Close_Window
norun:
pop BX
pop CX
pop DX
pop DI
pop SI
pop BP
pop ES
cli
mov SS,SSsave ; switch back to user's stack
mov SP,SPsave
;
mov AX,FLsave ; get original user's flags before INT 21h
push AX ; sneak them into flag register
popf
;
pop AX ; dummy pop to get flags off stack
pop DS ; restore registers left on user's stack
pop AX ; now get real AX
IFE TESTING
pushf
cli ; give interrupt code IF = 0 like normal
call CS:[DWORD PTR Save21]
ENDIF
push AX ; use USERS'S stack for first 3 words
push DS
pushf ; they will get used this time
;
cli
mov AX,CS ; now switch to internal stack
mov DS,AX
mov SSsave,SS
mov SPsave,SP
mov SS,AX
mov SP,OFFSET Pstack
sti
;
push ES
push BP
push SI
push DI
push DX
push CX
push BX
mov BP,SP ; save base pointer to display reg's
mov ES,AX
cld ; clear direction flag for string operations
;
; Recover registers on USER'S stack
;
push ES
les BX,Ssave
mov AX,ES:[BX+0] ; get FLAGS on exit
mov FLsave,AX
mov AX,ES:[BX+2] ; get DS
mov DSsave,AX
mov AX,ES:[BX+4] ; get AX
mov AXsave,AX
mov AX,ES:[BX+6] ; get IP
mov IPsave,AX
mov AX,ES:[BX+8] ; get CS
mov CSsave,AX
pop ES
;
xor AL,AL
xchg AL,Ret_Flg ; read value and clear flag for next time
test AL,0ffh ; is flag set to display return value?
jz nostop
;
call Open_Window
call Show_Regs
call Disp_Ret ; display return code in AX and flags
call Get_Key ; wait for a key pressed
call Close_Window
nostop:
pop BX
pop CX
pop DX
pop DI
pop SI
pop BP
pop ES
cli
mov SS,SSsave
mov SP,SPsave
popf
pop DS
pop AX
retf 2
;
; Display return code in AX, carry and zero flags
;
Disp_Ret:
mov DX,OFFSET RCStr
mov DI,14
mov AX,AXsave
call OutWord
;
mov DX,OFFSET CFStr
mov DI,13
add DI,DX
mov AL,'0'
test FLsave,0001 ; carry flag is least significant bit
jz dcy
inc AL ; carry was set so change to '1'
dcy:
mov [DI],AL ; store it in string
add CX,0015h ; move cursor position
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
;
mov DX,OFFSET ZFStr
mov DI,12
add DI,DX
mov AL,'0'
test FLsave,0040h ; test zero flag
jz dzf
inc AL ; zero was set so change to '1'
dzf:
mov [DI],AL ; store it in string
add CX,0010h ; move cursor position
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
;
mov CX,0816h ; display some help
mov DX,OFFSET HlpStr5
mov AH,YELLOW
call WPrint
ret
;
; Display register names in window
;
Show_Regs:
mov BX,OFFSET W1 ; window
mov CX,0101h ; cursor position - row, col
mov DX,OFFSET RegStr1 ; message address
mov AH,YELLOW ; attribute
call WPrint
;
add CX,0100h ; go down one row
mov DX,OFFSET RegStr2
mov AH,WHITE
call WPrint
;
; Display register values
;
add CX,0100h ; down a row
mov AX,AXsave ; get user's AX
call Whexwd ; display hex word
;
push BP ; save base pointer for string display
mov DX,6 ; number of registers to show this loop
disreg:
add CX,0005h ; move to next register field
mov AX,[BP]
call Whexwd ; display hex word
add BP,2
dec DX
jnz disreg
;
add CX,0005h ; move to next register field
mov AX,SPsave ; display SP
add AX,6 ; add for 3 pushes we did
call Whexwd
;
add CX,0005h ; move to next register field
mov AX,DSsave ; display DS
call Whexwd
;
add CX,0005h ; display ES
mov AX,[BP]
call Whexwd
;
add CX,0005h
mov AX,SSsave ; display SS
call Whexwd
;
add CX,0005h
mov AX,CSsave ; display CS
call Whexwd
;
add CX,0005h
mov AX,IPsave ; display IP
call Whexwd
;
add CX,0005h
mov AX,FLsave ; display FLAGS
call Whexwd
pop BP ; restore base pointer so display routines
; can use it
ret
;
; Display HELP in Window
;
Show_Help:
mov CX,0802h ; cursor position - row, col
mov AH,LTRED ; attribute for char
mov AL,'S'
call WChar ; write one character with attribute
;
add CX,0001h ; add 1 to column number
mov DX,OFFSET HlpStr1 ; message address
mov AH,WHITE
call WPrint
;
add CX,0012h ; move column number
mov AH,LTRED ; attribute for char
mov AL,'R'
call WChar ; write one character with attribute
;
add CX,0001h ; move column number
mov DX,OFFSET HlpStr2
mov AH,WHITE
call WPrint
;
add CX,000ch
mov AH,LTRED
mov AL,'E'
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,'S'
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,'C'
call WChar
;
add CX,0001h
mov DX,OFFSET HlpStr3
mov AH,WHITE
call WPrint
;
add CX,000dh
mov AH,LTRED
mov AL,18h ; up arrow
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,19h ; down arrow
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,1bh ; left arrow
call WChar
;
add CX,0001h
mov AH,LTRED
mov AL,1ah ; right arrow
call WChar
;
add CX,0001h
mov DX,OFFSET HlpStr4
mov AH,WHITE
call WPrint
ret
;
; HextoDec converts a word in AX to an ASCII string
; Entry:
; AX = word to convert
; Exit:
; SI = Pointer to last two character of ASCII string in 'Astr'
;
HextoDec:
push AX
push CX
push DX
push DI
;
mov DI,OFFSET Astr
mov CX,10000
xor DX,DX
div CX ; num / 10000
add AL,'0'
stosb
mov AX,DX
mov CX,1000
xor DX,DX
div CX ; num / 1000
add AL,'0'
stosb
mov AX,DX
mov CX,100
xor DX,DX
div CX ; num / 100
add AL,'0'
stosb
mov AX,DX
mov CX,10
xor DX,DX
div CX ; num / 10
add AL,'0'
stosb
mov AX,DX
add AL,'0'
stosb
xor AL,AL ; <NULL> terminator in string
stosb
sub DI,3 ; back up pointer
mov SI,DI
;
pop DI
pop DX
pop CX
pop AX
ret
;
; Display the text description of the current DOS function code
;
Disp_Text:
mov AX,AXsave ; get user's function code
cmp AH,63h ; is it in range?
jnb not_fnd ; jump if no
mov DI,OFFSET FCtbl
mov CX,LENFC / 6 ; number of entries
cmpdt:
cmp AH,[DI+1] ; is this the right function?
jz dtexec
add DI,6 ; no, point to next
loop cmpdt
not_fnd:
mov DX,OFFSET STRUN
call Disp_Str
ret
dtexec:
mov DX,[DI+2] ; get pointer to string
call [WORD PTR DI+4] ; go to display routine
ret
;
; Display string of DOS function code description
;
; Entry:
; DX = pointer to string
;
Disp_Str:
mov CX,0501h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Only one string must be inserted.
; It is pointed to by user's DS:DX.
; Entry:
; DX = text string containing description of function call
; DI = offset within local string (DX) to put user's (DS:DX)
; CX = max length before you will hit right side of Window
;
One_String:
add DI,DX
push DS
mov DS,DSsave
mov SI,[BP+REGDX] ; get USER's DS:DX value
rep movsb ; copy user's memory to text string
pop DS
call Disp_Str
ret
;
; Convert users's DS and DX to ASCII, imbed them in target string
; Entry:
; DX = pointer to string
; DI = offset where to put converted DS:DX
;
OutDSDX:
add DI,DX
mov AX,DSsave ; get user's DS
call Shexwrd
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; get user's DX
call Shexwrd
call Disp_Str
ret
;
; Convert word in AX to ASCII, imbed it in target string
; Entry:
; AX = word to convert
; DX = pointer to string
; DI = offset where to put converted AX
;
OutWord:
add DI,DX
call Shexwrd
call Disp_Str
ret
;
; Convert 'AL' to ASCII and imbed it in target string
; Entry:
; DX = target string
; DI = offset to put converted 'AL'
; AL = value to convert
;
OutByte:
add DI,DX
call Shexbyt
call Disp_Str
ret
;
; Routines to build string for display - some values need to be filled in
;
; Entry:
; DX = pointer to string
;
Disp_02:
Disp_04:
Disp_05:
mov DI,DX
add DI,22 ; offset this many into string
mov AX,[BP+REGDX] ; DL register has char to output
call Shexbyt ; convert it to ASCII
mov [DI+8],AL ; show hex byte
call Disp_Str
ret
;
; Direct Keyboard/Display I/O
;
Disp_06:
call Disp_Str
mov AX,[BP+REGDX] ; DL register has I/O type
mov DX,OFFSET STR06I
cmp AL,0ffh ; input character?
jz d06io
mov DX,OFFSET STR02 ; no, output character in 'DL'
mov DI,DX
add DI,22 ; offset this many into string
call Shexbyt ; convert it to ASCII
mov [DI+8],AL ; show hex byte
d06io:
add CX,0015h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Display String
; Entry:
; DX = pointer to string
;
Disp_09:
mov DI,18 ; offset where (DS:DX) goes within string
add DI,DX
mov cx,52 ; max number of char's to fit in window
push DS
mov DS,DSsave
mov SI,[BP+REGDX] ; get USER's DS:DX value
rep movsb ; copy user's memory to text string
pop DS
mov DI,18
add DI,DX
mov CX,52 ; max # of char's we care about
mov AL,'$' ; search for '$' terminator
repne scasb
jnz d09 ; jump if '$' not in first 52 chars
dec DI
mov BYTE PTR [DI],00 ; replace with <NULL> terminator
d09:
call Disp_Str
ret
Disp_39:
Disp_3a:
Disp_3b:
Disp_3c:
Disp_3d:
Disp_41:
Disp_5a:
Disp_5b:
mov DI,18 ; offset where (DS:DX) goes within string
mov cx,52 ; max number of char's to fit in window
call One_String
ret
Disp_0a:
Disp_23:
mov DI,27
call OutDSDX
ret
;
; Clear Keyboard and Do Function
;
Disp_0c:
mov DI,31
mov AX,AXsave ; AL register has function number
call OutByte
ret
;
; Select Disk
;
Disp_0e:
mov DI,12
mov AX,[BP+REGDX] ; DL register has char to output
call OutByte
ret
;
; Open File Using FCB
;
Disp_0f:
mov DI,23
call OutDSDX
ret
;
; Close File Using FCB
;
Disp_10:
mov DI,24
call OutDSDX
ret
;
; Search For First Matching File Using FCB
;
Disp_11:
mov DI,44
call OutDSDX
ret
;
; Search For Next Matching File Using FCB
;
Disp_12:
mov DI,43
call OutDSDX
ret
;
; Delete File Using FCB
; Create File Using FCB
; Rename File Using FCB
;
Disp_13:
Disp_16:
Disp_17:
mov DI,25
call OutDSDX
ret
;
; Read Sequential File Record Using FCB
;
Disp_14:
mov DI,41
call OutDSDX
ret
;
; Write Sequential File Record Using FCB
;
Disp_15:
mov DI,42
call OutDSDX
ret
;
; Set Disk Transfer Address
;
Disp_1a:
mov DI,29
call OutDSDX
ret
;
; Get FAT Information For Drive
;
Disp_1c:
mov DI,30
mov AX,[BP+REGDX] ; DL register has drive number
call OutByte
ret
;
; Read Random File Record Using FCB
; Set Random Record Field Using FCB
;
Disp_21:
Disp_24:
mov DI,37
call OutDSDX
ret
;
; Write Random File Record Using FCB
;
Disp_22:
mov DI,38
call OutDSDX
ret
;
; Set Interrupt Vector
;
Disp_25:
mov DI,DX
add DI,21
mov AX,AXsave ; AL has interrupt vector number
call Shexbyt
mov DI,28
call OutDSDX
ret
;
; Create New Program Segment
;
Disp_26:
mov DI,38
mov AX,[BP+REGDX] ; get user's DX
call OutWord
ret
;
; Read Random File Records
;
Disp_27:
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX register has record count
call Shexwrd
mov DI,44
call OutDSDX
ret
;
; Write Random File Records
;
Disp_28:
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX register has record count
call Shexwrd
mov DI,45
call OutDSDX
ret
;
; Parse Filename
;
Disp_29:
mov DI,18 ; offset where (DS:SI) goes within string
mov cx,52 ; max number of char's to fit in window
add DI,DX
push DI ; save for scan later
push DS
mov DS,DSsave
mov SI,[BP+REGSI] ; get USER's DS:SI value
rep movsb ; copy user's memory to text string
pop DS
;
; look for <CR> in string and put <NULL> terminator there
;
pop DI
mov AL,CR
mov cx,52
repne scasb
jnz dpf
dec DI
xor AL,AL
mov [DI],AL
dpf:
call Disp_Str
ret
;
; Set Date
;
Disp_2b:
mov DI,DX
add DI,22
mov AX,[BP+REGDX] ; DX register has month/day
mov AL,AH
xor AH,AH
call HextoDec ; convert month
movsb
movsb
inc DI ; skip past '/'
mov AX,[BP+REGDX]
xor AH,AH
call HextoDec ; convert day
movsb
movsb
inc DI ; skip past '/'
mov AX,[BP+REGCX]
call HextoDec ; convert year
movsb
movsb
call Disp_Str
ret
;
; Set Time
;
Disp_2d:
mov DI,DX
add DI,33
mov AX,[BP+REGCX] ; CX register has hours/minutes
mov AL,AH
xor AH,AH
call HextoDec ; convert hours
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGCX]
xor AH,AH
call HextoDec ; convert minutes
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; DX has seconds/hundreds of seconds
mov AL,AH
xor AH,AH
call HextoDec ; convert seconds
movsb
movsb
inc DI ; skip past ':'
mov AX,[BP+REGDX]
xor AH,AH
call HextoDec ; convert hundreds
movsb
movsb
call Disp_Str
ret
;
; Set Disk Write Verification
;
Disp_2e:
mov DI,DX
add DI,28
mov AX,AXsave ; AL register has verify switch
mov SI,OFFSET OFFstr
cmp AL,00 ; AL = 0 means OFF
jz verptr
mov SI,OFFSET ONstr
cmp AL,01 ; AL = 1 means ON
jz verptr
mov SI,OFFSET Blanks3 ; unknown code
verptr:
mov CX,3
rep movsb
call Disp_Str
ret
;
; Get/Set Control-Break Status
;
Disp_33:
mov AX,AXsave ; AL register has get/set switch
cmp AL,01 ; AL = 1 for SET
jz setcbs
cmp AL,00 ; AL = 0 for GET
jnz unk33 ; jump if unknown code
mov DX,OFFSET STR33G
unk33:
call Disp_Str
ret
setcbs:
mov DX,OFFSET STR33S ; point to 'SET' string
mov DI,DX
add DI,25
mov AX,[BP+REGDX] ; DL has set code
mov SI,OFFSET OFFstr
cmp AL,00 ; AL = 00 means OFF
jz gscbs
mov SI,OFFSET ONstr
cmp AL,01 ; AL = 01 means ON
jz gscbs
mov SI,OFFSET Blanks3
gscbs:
mov CX,3
rep movsb
call Disp_Str
ret
;
; Get Interrupt Vector
;
Disp_35:
mov DI,21
mov AX,AXsave ; AL has interrupt vector number
call OutByte
ret
;
; Get Disk Free Space On Drive
;
Disp_36:
mov DI,29
mov AX,[BP+REGDX] ; DL register has drive code
call OutByte
ret
;
; Close File Handle
;
Disp_3e:
mov DI,18
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Duplicate File Handle
;
Disp_45:
mov DI,22
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Read From File or Device
;
Disp_3f:
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has number of bytes to read
call Shexwrd
mov DI,37
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
; Write To File or Device
;
Disp_40:
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has number of bytes to read
call Shexwrd
mov DI,36
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
; Move File Pointer
;
Disp_42:
mov DI,DX
add DI,17
mov AX,[BP+REGBX] ; BX register has file handle
call Shexwrd
add DI,13
mov AX,[BP+REGCX] ; CX has upper half of offset
call Shexwrd
inc DI ; skip past ':'
mov AX,[BP+REGDX] ; CX has lower half of offset
call Shexwrd
add DI,7
mov AX,AXsave ; AL has method code
mov SI,OFFSET BOFstr
cmp AL,00 ; beginning of file?
jz mvptr
mov SI,OFFSET CURstr
cmp AL,01 ; current location?
jz mvptr
mov SI,OFFSET EOFstr
cmp AL,02 ; end of file?
jz mvptr
mov SI,OFFSET Blanks17 ; unknown
mvptr:
mov cx,17 ; string length
rep movsb
call Disp_Str
ret
;
; Get/Set file attributes
;
Disp_43:
mov AX,AXsave ; user's AX has get/set flag
cmp AL,00 ; 'get' code?
jz fgptr
cmp AL,01 ; 'set' code?
jz fsptr
call Disp_Str ; unknown code
ret
fgptr:
mov DX,OFFSET STR43G ; point to GET string
jmp SHORT faptr
;
fsptr:
mov DX,OFFSET STR43S ; point to SET string
faptr:
mov DI,18
mov cx,52 ; max number of char's to fit in window
call One_String
ret
;
; I/O Control For Devices
;
Disp_44:
mov AX,AXsave
cmp AL,00
jz jd440
cmp AL,01
jz jd441
cmp AL,02
jz jd442
cmp AL,03
jz jd443
cmp AL,04
jz jd444
cmp AL,05
jz jd445
cmp AL,06
jz jd446
cmp AL,07
jz jd447
cmp AL,08
jz jd448
cmp AL,11
jz jd4411
call Disp_Str ; unknown code
ret
jd440: jmp d440
jd441: jmp d441
jd442: jmp d442
jd443: jmp d443
jd444: jmp d444
jd445: jmp d445
jd446: jmp d446
jd447: jmp d447
jd448: jmp d448
jd4411: jmp d4411
d440:
mov DX,OFFSET STR440 ; Get Info For Device
mov DI,20
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d441:
mov DX,OFFSET STR441 ; Set Info For Device
mov DI,DX
add DI,20
mov AX,[BP+REGBX] ; BX has file handle
call Shexwrd
mov DI,29
mov AX,[BP+REGDX] ; DX has device information
call OutWord
ret
;
d442:
mov DX,OFFSET STR442 ; Read From Drive Control Channel
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,52
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d443:
mov DX,OFFSET STR443 ; Write To Drive Control Channel
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,51
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d444:
mov DX,OFFSET STR444 ; Read From Control Channel of Drive
mov DI,DX
add DI,5
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,47
mov AX,[BP+REGBX] ; BL has drive
call OutByte
ret
;
d445:
mov DX,OFFSET STR445 ; Write To Control Channel of Drive
mov DI,DX
add DI,6
mov AX,[BP+REGCX] ; CX has byte count
call Shexwrd
mov DI,46
mov AX,[BP+REGBX] ; BL has drive
call OutByte
ret
;
d446:
mov DX,OFFSET STR446 ; Get Input Status of Device
mov DI,27
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d447:
mov DX,OFFSET STR447 ; Get Output Status of Device
mov DI,28
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d448:
mov DX,OFFSET STR448 ; Report Whether Device Has Removable Media
mov DI,22
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
d4411:
mov DX,OFFSET STR4411 ; Set Retries For Device
mov DI,DX
add DI,23
mov AX,[BP+REGBX] ; BX has file handle
call Shexwrd
add DI,5
mov AX,[BP+REGDX] ; DX has retry count
call Shexwrd
mov DI,55
mov AX,[BP+REGCX] ; CX has interval between tries
call OutWord
ret
;
; Force Duplication of Handle
;
Disp_46:
mov DI,DX
add DI,28
mov AX,[BP+REGBX] ; BX has the existing file handle
call Shexwrd
mov DI,37
mov AX,[BP+REGCX] ; CX has the second file handle
call OutWord
ret
;
; Get Current Directory
;
Disp_47:
mov DI,DX
add DI,31
mov AX,[BP+REGDX] ; DL register has drive code
call Shexbyt
add DI,7
mov AX,DSsave
call Shexwrd
inc DI ; skip ':'
mov AX,[BP+REGSI] ; get USER's DS:SI value
call Shexwrd
call Disp_Str
ret
;
; Allocate Memory
;
Disp_48:
mov DI,9
mov AX,[BP+REGBX] ; BX has the memory requested in paragraphs
call OutWord
ret
;
; Free Allocated Memory
;
Disp_49:
mov DI,33
mov AX,[BP+REGES] ; ES has the segment address
call OutWord
ret
;
; Modify Memory Block
;
Disp_4a:
mov DI,DX
add DI,31
mov AX,[BP+REGES] ; ES has the segment address
call Shexwrd
mov DI,43
mov AX,[BP+REGBX] ; BX has size in paragraphs
call OutWord
ret
;
; Load or Exececute Program
; Find First Matching File
;
Disp_4b:
Disp_4e:
mov DI,29 ; offset where (DS:DX) goes within string
mov cx,41 ; max number of char's to fit in window
call One_String
ret
;
; Terminate Process with Return Code
;
Disp_4c:
mov DI,35
mov AX,Axsave ; AL register return code
call OutByte
ret
;
; Rename File
;
Disp_56:
mov DI,29
mov cx,41
call One_String ; display 'old' name
;
mov DX,OFFSET STR56N
mov DI,DX
add DI,29
push DS
mov DS,[BP+REGES]
mov SI,[BP+REGDI] ; get USER's ES:DI value
mov cx,41 ; to display 'new' name
rep movsb
pop DS
mov CX,0601h
mov BX,OFFSET W1
mov AH,HIWHITE
call WPrint
ret
;
; Get Date and Time of File
;
Disp_57:
mov AX,AXsave ; user's AL has get/set indicator
cmp AL,00 ; is it GET?
jz gdtptr
cmp AL,01 ; is it SET?
jz sdtptr
mov DI,37 ; unknown function
mov AX,[BP+REGBX] ; file handle
call OutWord
ret
gdtptr:
mov DX,OFFSET STR57G
jmp SHORT ddtptr
;
sdtptr:
mov DX,OFFSET STR57S
ddtptr:
mov DI,33
mov AX,[BP+REGBX] ; BX register has file handle
call OutWord
ret
;
; Lock/Unlock File
;
Disp_5c:
mov AX,AXsave
cmp AL,00 ; 0 = Lock
jz dlck
cmp AL,01 ; 1 = Unlock
jz dunlck
mov DI,17
mov AX,[BP+REGBX] ; BX has file handle
call OutWord
ret
;
dlck:
mov DX,OFFSET STR5c0
mov DI,10
mov AX,[BP+REGBX]
call OutWord
ret
;
dunlck:
mov DX,OFFSET STR5c1
mov DI,12
mov AX,[BP+REGBX]
call OutWord
ret
;
; Table of function codes.
; (1st) word is DOS function code (AH),
; (2nd) word is pointer to string to display,
; (3rd) word is subroutine address to handle display of this type function.
;
FCtbl:
dw 0000h, STR00, Disp_Str
dw 0100h, STR01, Disp_Str
dw 0200h, STR02, Disp_02
dw 0300h, STR03, Disp_Str
dw 0400h, STR04, Disp_04
dw 0500h, STR05, Disp_05
dw 0600h, STR06, Disp_06
dw 0700h, STR07, Disp_Str
dw 0800h, STR08, Disp_Str
dw 0900h, STR09, Disp_09
dw 0a00h, STR0a, Disp_0a
dw 0b00h, STR0b, Disp_Str
dw 0c00h, STR0c, Disp_0c
dw 0d00h, STR0d, Disp_Str
dw 0e00h, STR0e, Disp_0e
dw 0f00h, STR0f, Disp_0f
dw 1000h, STR10, Disp_10
dw 1100h, STR11, Disp_11
dw 1200h, STR12, Disp_12
dw 1300h, STR13, Disp_13
dw 1400h, STR14, Disp_14
dw 1500h, STR15, Disp_15
dw 1600h, STR16, Disp_16
dw 1700h, STR17, Disp_17
dw 1800h, STRUN, Disp_Str
dw 1900h, STR19, Disp_Str
dw 1a00h, STR1a, Disp_1a
dw 1b00h, STR1b, Disp_Str
dw 1c00h, STR1c, Disp_1c
dw 1d00h, STRUN, Disp_Str
dw 1e00h, STRUN, Disp_Str
dw 1f00h, STRUN, Disp_Str
dw 2000h, STRUN, Disp_Str
dw 2100h, STR21, Disp_21
dw 2200h, STR22, Disp_22
dw 2300h, STR23, Disp_23
dw 2400h, STR24, Disp_24
dw 2500h, STR25, Disp_25
dw 2600h, STR26, Disp_26
dw 2700h, STR27, Disp_27
dw 2800h, STR28, Disp_28
dw 2900h, STR29, Disp_29
dw 2a00h, STR2a, Disp_Str
dw 2b00h, STR2b, Disp_2b
dw 2c00h, STR2c, Disp_Str
dw 2d00h, STR2d, Disp_2d
dw 2e00h, STR2e, Disp_2e
dw 2f00h, STR2f, Disp_Str
dw 3000h, STR30, Disp_Str
dw 3100h, STR31, Disp_Str
dw 3200h, STRUN, Disp_Str
dw 3300h, STR33, Disp_33
dw 3400h, STRUN, Disp_Str
dw 3500h, STR35, Disp_35
dw 3600h, STR36, Disp_36
dw 3700h, STR37, Disp_Str
dw 3800h, STR38, Disp_Str
dw 3900h, STR39, Disp_39
dw 3a00h, STR3a, Disp_3a
dw 3b00h, STR3b, Disp_3b
dw 3c00h, STR3c, Disp_3c
dw 3d00h, STR3d, Disp_3d
dw 3e00h, STR3e, Disp_3e
dw 3f00h, STR3f, Disp_3f
dw 4000h, STR40, Disp_40
dw 4100h, STR41, Disp_41
dw 4200h, STR42, Disp_42
dw 4300h, STR43, Disp_43
dw 4400h, STR44, Disp_44
dw 4500h, STR45, Disp_45
dw 4600h, STR46, Disp_46
dw 4700h, STR47, Disp_47
dw 4800h, STR48, Disp_48
dw 4900h, STR49, Disp_49
dw 4a00h, STR4a, Disp_4a
dw 4b00h, STR4b, Disp_4b
dw 4c00h, STR4c, Disp_4c
dw 4d00h, STR4d, Disp_Str
dw 4e00h, STR4e, Disp_4e
dw 4f00h, STR4f, Disp_Str
dw 5000h, STRUN, Disp_Str
dw 5100h, STRUN, Disp_Str
dw 5200h, STRUN, Disp_Str
dw 5300h, STRUN, Disp_Str
dw 5400h, STR54, Disp_Str
dw 5500h, STRUN, Disp_Str
dw 5600h, STR56, Disp_56
dw 5700h, STR57, Disp_57
dw 5800h, STRUN, Disp_Str
dw 5900h, STR59, Disp_Str
dw 5a00h, STR5a, Disp_5a
dw 5b00h, STR5b, Disp_5b
dw 5c00h, STR5c, Disp_5c
dw 5d00h, STRUN, Disp_Str
dw 5e00h, STRUN, Disp_Str
dw 5f00h, STRUN, Disp_Str
dw 6000h, STRUN, Disp_Str
dw 6100h, STRUN, Disp_Str
dw 6200h, STR62, Disp_Str
LENFC EQU $ - FCtbl
;
; The XX's are just place holders for help in alignment during debugging
;
STR00 db 'Terminate Program'
db 0
STR01 db 'Keyboard Input With Echo'
db 0
STR02 db 'Output Character Hex XX ASCII X'
db 0
STR03 db 'Serial Input'
db 0
STR04 db 'Serial Output Hex XX ASCII X'
db 0
STR05 db 'Printer Output Hex XX ASCII X'
db 0
STR06 db 'Direct Console I/O - '
db 0
STR06I db 'Input Character'
db 0
STR07 db 'Direct Console Input Without Echo'
db 0
STR08 db 'Console Input Without Echo'
db 0
STR09 db 'Display String -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR0a db 'Buffered Keyboard Input To XXXX:XXXXH'
db 0
STR0b db 'Check Standard Input Status'
db 0
STR0c db 'Clear Keyboard and Do Function XXH'
db 0
STR0d db 'Reset Disk'
db 0
STR0e db 'Select Disk XXH'
db 0
STR0f db 'Open File Using FCB at XXXX:XXXXH'
db 0
STR10 db 'Close File Using FCB at XXXX:XXXXH'
db 0
STR11 db 'Search For First Matching File Using FCB at XXXX:XXXXH'
db 0
STR12 db 'Search For Next Matching File Using FCB at XXXX:XXXXH'
db 0
STR13 db 'Delete File Using FCB at XXXX:XXXXH'
db 0
STR14 db 'Read Sequential File Record Using FCB at XXXX:XXXXH'
db 0
STR15 db 'Write Sequential File Record Using FCB at XXXX:XXXXH'
db 0
STR16 db 'Create File Using FCB at XXXX:XXXXH'
db 0
STR17 db 'Rename File Using FCB at XXXX:XXXXH'
db 0
STR19 db 'Report Current Drive'
db 0
STR1a db 'Set Disk Transfer Address To XXXX:XXXXH'
db 0
STR1b db 'Get FAT Information For Default Drive'
db 0
STR1c db 'Get FAT Information For Drive XXH'
db 0
STR21 db 'Read Random File Record Using FCB at XXXX:XXXXH'
db 0
STR22 db 'Write Random File Record Using FCB at XXXX:XXXXH'
db 0
STR23 db 'Get File Size Using FCB at XXXX:XXXXH'
db 0
STR24 db 'Set Random Record Field Using FCB at XXXX:XXXXH'
db 0
STR25 db 'Set Interrupt Vector XXH to XXXX:XXXXH'
db 0
STR26 db 'Create New Program Segment At Segment XXXXH'
db 0
STR27 db 'Read XXXXH Random File Records Using FCB at XXXX:XXXXH'
db 0
STR28 db 'Write XXXXH Random File Records Using FCB at XXXX:XXXXH'
db 0
STR29 db 'Parse Filename -->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR2a db 'Get Date'
db 0
STR2b db 'Set Date To mm/dd/yy XX/XX/XX'
db 0
STR2c db 'Get Time'
db 0
STR2d db 'Set Time To Hrs:Mins:Secs:Hunds XX:XX:XX:XX'
db 0
STR2e db 'Set Disk Write Verification XXX'
db 0
STR2f db 'Get Disk Transfer Address'
db 0
STR30 db 'Get DOS Version Number'
db 0
STR31 db 'Terminate Process and Remain Resident'
db 0
STR33 db 'Get/Set Control-Break Status'
db 0
STR33G db 'Get Control-Break Status'
db 0
STR33S db 'Set Control-Break Status XXX'
db 0
STR35 db 'Get Interrupt Vector XXH'
db 0
STR36 db 'Get Disk Free Space On Drive XXH'
db 0
STR37 db 'Get DOS Switch Character'
db 0
STR38 db 'Get/Set Country Dependent Information'
db 0
STR39 db 'Create Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3a db 'Remove Subdir --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3b db 'Change Dir To --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3c db 'Create File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3d db 'Open File ------->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR3e db 'Close File Handle XXXXH'
db 0
STR3f db 'Read XXXXH Bytes From File or Device XXXXH'
db 0
STR40 db 'Write XXXXH Bytes To File or Device XXXXH'
db 0
STR41 db 'Delete File ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR42 db 'Move File Handle XXXXH Pointer By XXXX:XXXXH From '
db 'XXXXXXXXXXXXXXXXX'
db 0
STR43 db 'Get/Set File Attributes'
db 0
STR43G db 'Get File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR43S db 'Set File Attrib ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR44 db 'I/O Control For Devices'
db 0
STR440 db 'Get Info For Device XXXXH'
db 0
STR441 db 'Set Info For Device XXXXH to XXXXH'
db 0
STR442 db 'Read XXXXH Bytes From Drive Control Channel of File XXXXH'
db 0
STR443 db 'Write XXXXH Bytes To Drive Control Channel of File XXXXH'
db 0
STR444 db 'Read XXXXH Bytes From Control Channel of Drive XXH'
db 0
STR445 db 'Write XXXXH Bytes To Control Channel of Drive XXH'
db 0
STR446 db 'Get Input Status of Device XXXXH'
db 0
STR447 db 'Get Output Status of Device XXXXH'
db 0
STR448 db 'Report Whether Device XXXXH Has Removable Media'
db 0
STR4411 db 'Set Retries For Device XXXXH to XXXXH With Interval of XXXXH'
db 0
STR45 db 'Duplicate File Handle XXXXH'
db 0
STR46 db 'Force Duplication of Handle XXXXH to XXXXH'
db 0
STR47 db 'Get Current Directory of Drive XXH into XXXX:XXXXH'
db 0
STR48 db 'Allocate XXXXH Paragraphs of Memory'
db 0
STR49 db 'Free Allocated Memory at Segment XXXXH'
db 0
STR4a db 'Modify Memory Block at Segment XXXXH to be XXXXH Paragraphs'
db 0
STR4b db 'Load or Execute Program ---->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR4c db 'Terminate Process With Return Code XXH'
db 0
STR4d db 'Get Return Code of Subprocess'
db 0
STR4e db 'Find First Matching File --->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR4f db 'Find Next Matching File'
db 0
STR54 db 'Get Verify State'
db 0
STR56 db 'Rename File Old Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR56N db ' New Name ----->XXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXX'
db 0
STR57 db 'Get/Set Date and Time of File Handle XXXXH'
db 0
STR57G db 'Get Date and Time of File Handle XXXXH'
db 0
STR57S db 'Set Date and Time of File Handle XXXXH'
db 0
STR59 db 'Get Extended Error Code'
db 0
STR5a db 'Create Temp File->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR5b db 'Create New File ->XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
db 'XXXXXXXXXXXL'
db 0
STR5c db 'Lock/Unlock File XXXXH'
db 0
STR5c0 db 'Lock File XXXXH'
db 0
STR5c1 db 'Unlock File XXXXH'
db 0
STR62 db 'Get PSP Address'
db 0
STRUN db '** Undocumented Function Code **'
db 0
;
; Don't change the size of the following strings
;
Blanks3 db ' '
Blanks17 db ' '
ONstr db 'ON '
OFFstr db 'OFF'
BOFstr db 'Beginning of File'
CURstr db 'Current Location '
EOFstr db 'End of File '
RCStr db 'Return Code = XXXXH'
db 0
CFStr db 'Carry Flag = X'
db 0
ZFStr db 'Zero Flag = X'
db 0
Open_Window:
push BP
push ES
;
; Calculate current page offset each time since it can change at any time
;
mov AH,0fh ; get current video state
int 10h
mov CL,BH ; returns BH = active page #
xor CH,CH
mov AX,0100h ; page length in paragraphs
mul cx
add AX,Scrseg ; add base segment of screen
mov Pageseg,AX
;
; Save current contents of window area
;
mov BX,OFFSET W1 ; window parameters
mov SI,[BX].startmem ; screen addr of start of window
mov DX,[BX].height
mov ES,Winseg ; point to allocated memory block
mov DI,0000
saverow:
push DS
mov CX,[BX].xwidth
mov DS,Pageseg ; get screen segment
push SI ; save screen offset
rep movsw ; do word to get char and attribute
pop SI
pop DS
add SI,BytesPL ; next row down
dec DX
jnz saverow
;
; Draw window
;
mov ES,Pageseg ; get screen segment
mov DI,[BX].startmem ; physical addr of start of window
mov AH,HIWHITE
;
; Draw top border
;
push DI
mov AL,ULC ; write upper left corner
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BRDROW
rep stosw
mov AL,URC ; write upper right corner
stosw
pop DI
add DI,BytesPL ; next row down
;
; Put version along top
;
push AX ; save attribute
push DI ; and scrren pointer for next row
mov CX,LENVER
shr CX,1 ; divide string length by 2
mov AX,[BX].xwidth
shr AX,1 ; divide window width by 2
sub AX,CX
mov DI,[BX].startmem
shl AX,1 ; difference times 2 for char + attr
add DI,AX
mov AH,74h ; attribute for string (Red on White)
mov SI,OFFSET VERmsg
mov CX,LENVER
putver:
lodsb
stosw
loop putver
pop DI
pop AX
;
; Draw middle of window
;
mov DX,[BX].height
sub DX,2
winrows:
push DI
mov AL,BRDCOL ; left border column
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BLANK
rep stosw
mov AL,BRDCOL ; right border column
stosw
pop DI
add DI,BytesPL ; next row down
dec DX
jnz winrows
;
; Draw bottom border
;
push DI
mov AL,LLC ; write lower left corner
stosw
mov CX,[BX].xwidth
sub CX,2
mov AL,BRDROW
rep stosw
mov AL,LRC ; write lower right corner
stosw
pop DI
;
pop ES
pop BP
ret
Close_Window:
push ES
mov BX,OFFSET W1
mov DI,[BX].startmem ; physical addr of screen area
mov ES,Pageseg ; point to allocated memory block
mov SI,0000 ; start of save memory block
mov DX,[BX].height
resrow:
push DS
mov CX,[BX].xwidth
mov DS,Winseg ; get saved memory segment
push DI ; save screen offset
rep movsw ; do word to get char and attribute
pop DI
pop DS
add DI,BytesPL ; next row down
dec DX
jnz resrow
pop ES
ret
;
; Print a string in window.
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AH = Attribute
; DX = addr of string
;
WPrint:
push ES
call GetRC ; convert to row, col in DI
mov ES,Pageseg
mov SI,DX ; move string address
wpwrt:
cmp BYTE PTR [SI],00 ; test for string terminator <NULL>
jz wpexit
lodsb
stosw
jmp wpwrt
wpexit:
pop ES
ret
;
; Write one character and attribute to window
;
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AH = attr
; AL = char
;
WChar:
push ES
call GetRC ; convert to row, col in DI
mov ES,Pageseg
stosw
pop ES
ret
;
; Convert row, col in CX to physical addr in DI
;
GetRC:
push AX
push DX
mov DI,[BX].startmem ; physical start of window memory
add DI,BytesPL ; go down a row
add DI,2 ; go in one char, this is 0,0
mov AL,CH
xor AH,AH ; AX = relative row number
mul BytesPL ; this clobbers DX
add DI,AX
mov AX,CX ; restore coordinates
xor AH,AH ; AX = relative col number
shl AX,1 ; times 2 for attribute
add DI,AX
pop DX
pop AX
ret
;
; WRITE HEX WORD
; Convert a hex word to an ASCII string and display it
; Entry:
; CX = Row, Col position relative to start of window
; BX = Window pointer
; AX = Word to convert
;
Whexwd:
push AX
push BX
push CX
push DX
;
push BX ; save window pointer
push CX ; and row, col
mov DI,OFFSET Astr
xchg AH,AL
call Shexbyt
xchg AH,AL
call Shexbyt
xor AL,AL
stosb ; make sure of terminating NULL
mov DX,OFFSET Astr
pop CX ; get row, col
pop BX ; and Window ptr
mov AH,HIWHITE ; set attribute
call WPrint
;
pop DX
pop CX
pop BX
pop AX
ret
;
; STORE HEX WORD
; Convert a hex word to ASCII and store it in destination string
; Entry:
; AX = Word to convert
; DI = destination pointer
;
Shexwrd:
xchg AL,AH ; convert upper half first
call Shexbyt
xchg AL,AH ; convert lower half
call Shexbyt
ret
;
; STORE HEX BYTE
; Convert a hex byte to ASCII and store it in destination string
; Entry:
; AL = Byte to convert
; DI = destination pointer
;
Shexbyt:
push AX
mov AH,AL ; save temporarily
shr AL,1
shr AL,1
shr AL,1
shr AL,1
cmp AL,10
jb wh1
add AL,07
wh1:
add AL,'0'
stosb
mov AL,AH
and AL,0fh
cmp AL,10
jb wh2
add AL,07
wh2:
add AL,'0'
stosb
pop AX
ret
;
; Check if key pressed requires special handling
;
; Entry:
; AX = key pressed
;
Disp_Key:
mov DI,OFFSET Keytbl ; keys and subroutine addresses
mov CX,LENKTAB / 4 ; number of entries
cmpdk:
cmp AX,[DI] ; is key in table?
jz dkexec
add DI,4 ; no, point to next key value
loop cmpdk
clc ; carry clear means exit upon return
ret
dkexec:
add DI,2
call [WORD PTR DI]
ret
;
; Table of keys to watch for followed by the address of the routine to execute
;
Keytbl dw ESCAPE, DO_Esc
dw BIGS, Do_Skey
dw SMALLS, Do_Skey
dw BIGR, Do_Rkey
dw SMALLR, Do_Rkey
dw UPARROW, Do_Up
dw DOWNARROW, Do_Down
dw LEFTARROW, Do_Left
dw RIGHTARROW, Do_Right
dw HOME, Do_Home
dw XEND, Do_End
dw PGUP, Do_Pgup
dw PGDN, Do_Pgdn
LENKTAB EQU $ - Keytbl
;
; If ESC key, clear 'running flag' so Int 21h will not be stopped each time
;
Do_Esc:
mov AL,00
mov Run_Flg,AL
clc ; carry clear means exit upon return
ret
;
; 'S' key - skip successive functions of current type.
; Return to intercepting calls when something new comes along.
; This is so you don't have to sit through dozens if Function '2' calls
; while the target program outputs a string to the display.
;
Do_Skey:
mov AL,0ffh
mov Skip_Flg,AL ; set flag to show we should skip something
mov AX,AXsave ; get current function code
mov Skip_Typ,AH ; save it
clc ; carry clear means exit upon return
ret
;
; 'R' key - stop after INT 21h call and let user see result registers
;
Do_Rkey:
mov AL,0ffh
mov Ret_Flg,AL ; set flag
clc ; carry clear means exit upon return
ret
;
; DO_Up - move window up one line
;
Do_Up:
mov BX,OFFSET W1
call Close_Window
mov AX,[BX].leftrow
or AX,AX ; already at top of screen?
jz upexit
dec [BX].leftrow
dec [BX].rightrow
call Window_Parms ; recalculate parameters
upexit:
stc ; don't exit upon return
ret
;
; DO_Down - move window down one line
;
Do_Down:
mov BX,OFFSET W1
call Close_Window
mov AX,[BX].rightrow
cmp AX,24 ; already at bottom of screen?
jz dnexit
inc [BX].leftrow
inc [BX].rightrow
call Window_Parms ; recalculate parameters
dnexit:
stc ; don't exit upon return
ret
;
; DO_Left - move window left one column
;
Do_Left:
mov BX,OFFSET W1
call Close_Window
mov AX,[BX].leftcol
or AX,AX ; already at left of screen?
jz lfexit
dec [BX].leftcol
dec [BX].rightcol
call Window_Parms ; recalculate parameters
lfexit:
stc ; don't exit upon return
ret
;
; DO_right - move window right one column
;
Do_Right:
mov BX,OFFSET W1
call Close_Window
mov AX,[BX].rightcol
cmp AX,79 ; already at right of screen?
jz rtexit
inc [BX].leftcol
inc [BX].rightcol
call Window_Parms ; recalculate parameters
rtexit:
stc ; don't exit upon return
ret
;
; Do_Home - move window to upper left corner
;
Do_Home:
mov BX,OFFSET W1
call Close_Window
xor AX,AX
mov [BX].leftrow,AX
mov [BX].leftcol,AX
;
mov AX,[BX].leftrow
add AX,[BX].height
dec AX
mov [BX].rightrow,AX
;
mov AX,[BX].leftcol
add AX,[BX].xwidth
dec AX
mov [BX].rightcol,AX
;
call Window_Parms ; recalculate parameters
stc ; don't exit upon return
ret
;
; Do_End - move window to lower left corner
;
Do_End:
mov BX,OFFSET W1
call Close_Window
mov AX,24
mov [BX].rightrow,AX
xor AX,AX
mov [BX].leftcol,AX
;
mov AX,[BX].rightrow
sub AX,[BX].height
inc AX
mov [BX].leftrow,AX
;
mov AX,[BX].leftcol
add AX,[BX].xwidth
dec AX
mov [BX].rightcol,AX
;
call Window_Parms ; recalculate parameters
stc ; don't exit upon return
ret
;
; Do_Pgup - move window to upper right corner
;
Do_Pgup:
mov BX,OFFSET W1
call Close_Window
xor AX,AX
mov [BX].leftrow,AX
mov AX,79
mov [BX].rightcol,AX
;
mov AX,[BX].leftrow
add AX,[BX].height
dec AX
mov [BX].rightrow,AX
;
mov AX,[BX].rightcol
sub AX,[BX].xwidth
inc AX
mov [BX].leftcol,AX
;
call Window_Parms ; recalculate parameters
stc ; don't exit upon return
ret
;
; Do_Pgdn - move window to lower right corner
;
Do_Pgdn:
mov BX,OFFSET W1
call Close_Window
mov AX,24
mov [BX].rightrow,AX
mov AX,79
mov [BX].rightcol,AX
;
mov AX,[BX].rightrow
sub AX,[BX].height
inc AX
mov [BX].leftrow,AX
;
mov AX,[BX].rightcol
sub AX,[BX].xwidth
inc AX
mov [BX].leftcol,AX
;
call Window_Parms ; recalculate parameters
stc ; don't exit upon return
ret
;
; Wait for any key pressed
;
Get_Key:
push BP ; just in case
mov AH,00
int 16h
pop BP
ret
;
; Calculate window parameters:
; 1) Physical starting address of window
; 2) Width of window in characters
; 3) Height of window
;
; Entry:
; BX = window pointer
; Exit:
; AX = Number of bytes contained in window
;
Window_Parms:
mov AX,[BX].leftrow
mul BytesPL ; multiply by bytes per line
mov CX,[BX].leftcol
shl CX,1 ; times 2 for attribute byte
add AX,CX
mov SI,AX ; starting physical address of window
mov [BX].startmem,AX ; save it for later
;
; Calculate size of window in bytes to allocate memory
;
mov AX,[BX].rightcol
inc AX
sub AX,[BX].leftcol
mov [BX].xwidth,AX
mov CX,[BX].rightrow
inc CX
sub CX,[BX].leftrow
mov [BX].height,CX
mul CL ; AX = nbr of bytes of screen area
shl AX,1 ; times 2 to get attributes also
ret
;
; Define format of WINDOW structure
;
Window STRUC
leftrow dw ?
leftcol dw ?
rightrow dw ?
rightcol dw ?
xwidth dw ?
height dw ?
startmem dw ?
Window ENDS
;
; Allocate and initialize WINDOW parameters
;
W1 Window <8, 2, 18, 74, 0, 0, 0>
Winseg dw 0000 ; store segment of allocated memory
; for saving screen data
Scrseg dw 0000 ; base segment for screen memory
Pageseg dw 0000 ; segment after page offset factored in
BytesPL dw 80*2 ; number of bytes per line (char + attr)
Run_Flg db 0ffh ; 'running' flag
Ret_Flg db 00 ; 'stop on return' flag
Sw_Char db '/' ; DOS switch character
;
; The following two variables are initialized the way they are to skip
; the first Int 21 call generated by 'STEPDOS' to EXEC the target program.
;
Skip_Typ db 4bh ; type of function call to skip temporarily
Skip_Flg db 0ffh ; set if function should be skipped
Save21 dw ? ; save original Int21 vector here, IP
dw ? ; and SEG
Ssave LABEL DWORD
SPsave dw ? ; save some of the user's registers here
SSsave dw ? ; others will be on local stack
AXsave dw ? ; these will have been left on user's
DSsave dw ? ; stack instead of local stack
CSsave dw ?
IPsave dw ?
FLsave dw ?
;
; Parameter block that will be passed to the EXEC function call (4bh) of DOS
;
Param_Block LABEL WORD
SegEnv dw ? ; segment addr of environment string
SegCmd dw ? ; segmented ptr to command line
dw ?
FCBptr1 dw ? ; segmented ptr to first FCB
dw ?
FCBptr2 dw ? ; segmented ptr to second FCB
dw ?
;
; File name that will be passed to the EXEC function call of DOS
;
Filename db 128 dup (0)
FNsize dw 0
;
; Command line from PSP:80h will be copied here to work from
;
PSPstr db 128 dup (0)
;
; Command Line that will be passed to the EXEC function call of DOS
;
CLstr db 128 dup (0)
;
; Two FCB's that will be passed to the EXEC function call of DOS
;
FCB1 db 0
db 11 dup (' ')
db 0, 0, 0, 0
FCB2 db 0
db 11 dup (' ')
db 0, 0, 0, 0
COMstr db '.COM'
EXEstr db '.EXE'
;
VERmsg db ' STEPDOS Version 1.2 '
LENVER EQU $ - VERmsg
Memerr db CR
db LF
db 'Error Allocating Window Memory$'
Execmsg db CR
db LF
db 'Unable to execute target program$'
Findmsg db CR
db LF
db 'Unable to find target program '
db 27h ; opening quote
db '$'
Umsg db CR
db LF
db 'Usage: STEPDOS filename$'
RegStr1 db ' AX BX CX DX DI SI BP SP'
db ' DS ES SS CS IP FL'
db 0
RegStr2 db '---- ---- ---- ---- ---- ---- ---- ----'
db ' ---- ---- ---- ---- ---- ----'
db 0
HlpStr1 db 'kip Current Func'
db 0
HlpStr2 db 'eturn Code'
db 0
HlpStr3 db ' - Non Stop'
db 0
HlpStr4 db ' - Move Window'
db 0
HlpStr5 db 'Press Any Key To Continue'
db 0
Astr db 32 dup (0) ; string for converting ASCII characters
;
; Local Program Stack Area
;
db 128 dup (?)
Pstack EQU $
;
; Target Stack Area
;
db 128 dup (?)
Tstack EQU $
IF TESTING
Istr db 128 dup (' ')
Ostr db 'Output String'
db 0
ENDIF
PRSIZE EQU $
Code ENDS
END Main